﻿#include "../control.h"
#include "../ctlHelp.h"
#include <algorithm>

namespace swui
{
	unsigned ctlRoot::getChildrenZOrderTopNumber()
	{
		return _eventTrans.zordNumber();
	}
	ctlRoot* ctlRoot::getChild(unsigned index)
	{
		if(index >= _eventTrans.getChildEnumerator().size())
			return nullptr;
		return _eventTrans.getChildEnumerator()[index];
	}
	controlList::const_iterator ctlRoot::begin()
	{
		return _eventTrans.getChildEnumerator().begin();
	}
	controlList::const_iterator ctlRoot::end()
	{
		return _eventTrans.getChildEnumerator().end();
	}
	std::vector<ctlRoot*>::const_pointer ctlRoot::_get_redraw_begin(unsigned)
	{
		return _eventTrans.getChildEnumerator().data();
	}
	unsigned ctlRoot::_get_redraw_end(unsigned)
	{
		return _eventTrans.getChildEnumerator().size();
	}
	std::vector<ctlRoot*>::const_pointer ctlRoot::_get_event_begin(unsigned)
	{
		return _eventTrans.getChildEnumerator().data()
			+ _eventTrans.getChildEnumerator().size() - 1;
	}
	unsigned ctlRoot::_get_event_end(unsigned)
	{
		return _eventTrans.getChildEnumerator().size();
	}
	unsigned ctlRoot::_get_redraw_or_event_number()
	{
		return 1;
	}
	bool ctlRoot::_combine_child_rgn(HRGN){ return false; }
	std::shared_ptr<ctlFontQueue> ctlRoot::getFontQueue()
	{
		return _eventTrans.getMajorInfo()->constantFont;
	}
	std::shared_ptr<ctlImageQueue> ctlRoot::getImageQueue()
	{
		return _eventTrans.getMajorInfo()->constantImage;
	}
	unsigned ctlRoot::getZOrder()
	{
		if(getParent() == nullptr) return 0;
		auto& enumetor = getParent()->_eventTrans.getChildEnumerator();
		return std::find(enumetor.begin(), enumetor.end(), this) - enumetor.begin();
	}
	bool ctlRoot::setZOrderTop()
	{
		if(getParent() == nullptr)
			return false;
		getParent()->_eventTrans.setZOrderTop(this);
		return setZOrder(getParent()->_eventTrans.getChildEnumerator().size() - 1);
	}
	bool ctlRoot::setZOrder(unsigned order)
	{
		if(getParent() == nullptr)
			return false;
		if(order >= getParent()->_eventTrans.getChildEnumerator().size()
			- getParent()->_eventTrans.isZOrderTop(this) ? 0
			: getParent()->getChildrenZOrderTopNumber())
			return false;
		_eventTrans.moveTo(order);
		return true;
	}
	bool ctlRoot::setZOrderAfter(ctlRoot* obj)
	{
		if(obj->getParent() != getParent() || obj == this)
			return false;
		unsigned objOrder = obj->getZOrder();
		return setZOrder(objOrder > getZOrder() ? objOrder : objOrder + 1);
	}
	bool ctlRoot::setZOrderBefore(ctlRoot* obj)
	{
		if(obj->getParent() != getParent() || obj == this)
			return false;
		unsigned objOrder = obj->getZOrder();
		return setZOrder(objOrder > getZOrder() ? objOrder - 1 : objOrder);
	}
	void ctlRoot::_basic_create_(ctlRect rect, ctlRoot* parent)
	{
		if(_styleBase) delete _styleBase;
		_moveX.format = _moveY.format = moveFormat::absolute;
		_sizeX.format = _sizeY.format = sizeFormat::absolute;
		_styleBase = nullptr;
		_focus_assign = nullptr;
		_textpack.clear();
		_redrawLockCount = 0;
		_isShow = true;
		_controlAlpha = 255;
		_isEnabled = true;
		_parent = parent;
		_rect = rect;
		_positionLockCount = 0;
		_moveThisAlignment = moveAlignment::leftTop;
		_moveRelationAlignment = moveAlignment::leftTop;
		_eventTrans.setRelation(this);
		if(parent != 0) 
		{
			_eventTrans.relateParent(parent);
			parent->_eventTrans.push(this);
		}
	}
	ctlRect ctlRoot::getAbsoluteRect()
	{
		ctlRect rc = getRect();
		ctlRoot* pre = getParent();
		while(pre)
		{
			rc.x += pre->getLeft();
			rc.y += pre->getTop();
			pre = pre->getParent();
		}
		return rc;
	}
	//重绘管理
	void ctlRoot::redraw()
	{
		redrawRect(getRect(), false);
	}

	bool ctlRoot::isVisible()
	{
		ctlRoot* pre = this;
		while(pre)
		{
			if(!pre->isShow()) return false;
			pre = pre->getParent();
		}
		return true;
	}
	ctlRoot::~ctlRoot()
	{
		destroy();
	}
	void ctlRoot::_control_destroy(bool isAllChild)
	{
		if(!isCreated()) return;
		_controlType = ctlControlType::ctlUndefined;
		if(_eventTrans.getMajorInfo()->hCaret.getLevel() == this)
		{
			_eventTrans.getMajorInfo()->hCaret.setLevel(nullptr);
			_eventTrans.getMajorInfo()->hCaret.setStatus(false);
		}
		if(getFocus() == this) killFocus();
		_textpack.clear();
		if(_styleBase) delete _styleBase;
		_styleBase = nullptr;
		for(ctlRoot* elem : *this)
			elem->_control_destroy(true);
		_eventTrans.clear();
		if(getRoot() != this && !isAllChild)
			getParent()->_eventTrans.pop(this);
		for(auto& elem : _heap_alloc_recorder)
		{
			if(elem.second != 0)
				elem.second(elem.first);
			delete[] elem.first;
		}
		_heap_alloc_recorder.clear();
		_mouse_method.clear();
		_key_method.clear();
		_position_method.clear();
		_notify_method.clear();
		_size_related.clear();
		_move_related.clear();
		_parent = 0;
	}
	void ctlRoot::destroy()
	{
		ctlRoot* parent = getParent();
		_control_destroy(false);
		if(parent) parent->redraw();
	}
	void ctlRoot::setStyle(const ctlStyleBase& info)
	{
		if(!isCreated() || !isEnabled()) return;
		if(_styleBase) delete _styleBase;
		_styleBase = info.clone();
		redraw();
	}
	std::shared_ptr<ctlStyleBase> ctlRoot::getStyle()
	{
		return std::shared_ptr<ctlStyleBase>(_styleBase->clone());
	}

	//文字信息
	bool ctlRoot::setText(const ctlText& lpszText)
	{
		if(!isCreated() || !isEnabled()) return false;
		_textpack.set(lpszText);
		redraw();
		return true;
	}
	unsigned ctlRoot::getTextLength()
	{
		return _textpack.length();
	}
	unsigned ctlRoot::getANSITextSize()
	{
		return _textpack.ansiLength();
	}
	unsigned ctlRoot::getText(char* lpszText, unsigned len)
	{
		return _textpack.get(lpszText, len);
	}
	unsigned ctlRoot::getText(std::wstring::pointer lpszText, unsigned len)
	{
		return _textpack.get(lpszText, len);
	}
	std::string ctlRoot::getText()
	{
		return _textpack.getstr();
	}
	std::wstring ctlRoot::getWideText()
	{
		return _textpack.getwidestr();
	}

	static bool _check_ring_relative_move(ctlRoot* src, ctlRoot* dest, ctlDirection dir)
	{
		if(src == dest) return true;
		ctlRoot *ra = src->getMoveRelation(dir);
		while(ra != nullptr)
		{
			if(ra == dest) return true;
			ra = ra->getMoveRelation(dir);
		}
		return false;
	}
	static bool _check_ring_relative_size(ctlRoot* src, ctlRoot* dest, ctlDirection dir)
	{
		if(src == dest) return true;
		ctlRoot *ra = src->getSizeRelation(dir);
		while(ra != nullptr)
		{
			if(ra == dest) return true;
			ra = ra->getSizeRelation(dir);
		}
		return false;
	}

	bool ctlRoot::size(int cx, int cy, bool absolute)
	{
		if(!isCreated() || !isEnabled() || isPositionLocked()
			|| (cx <= 0 && absolute) || (cy <= 0 && absolute))
			return false;
		ctlRect oldRect = getRect();
		ctlRect tempRect = getRect();
		if(absolute)
		{
			tempRect.cx = cx;
			tempRect.cy = cy;
		} else {
			tempRect.cx += cx;
			tempRect.cy += cy;
		}
		//发送 sizing 事件
		bool allowed = true;
		ctlPositionEvent pe;
		pe.eventType = ctlPositionEventType::sizeing;
		pe.nextHandler = &allowed;
		pe.position = ctlPoint(tempRect.cx, tempRect.cy);
		_position_event_(&pe);

		if(allowed)
		{
			_rect = tempRect;
			redraw();
			redrawRect(oldRect);
			//发送 size 事件
			pe.eventType = ctlPositionEventType::size;
			pe.position = ctlPoint(getWidth(), getHeight());
			_position_event_(&pe);
			return true;
		}
		return false;
	}
	bool ctlRoot::move(int x, int y, bool absolute)
	{
		if(!isCreated() || !isEnabled() || isPositionLocked()) return false;
		ctlRect oldRect = getRect();
		ctlRect tempRect = getRect();
		if(absolute)
		{
			tempRect.x = x;
			tempRect.y = y;
		} else {
			tempRect.x += x;
			tempRect.y += y;
		}
		//发送 moving 事件
		bool allowed = true;
		ctlPositionEvent pe;
		pe.eventType = ctlPositionEventType::moving;
		pe.isAllow = &allowed;
		pe.position = ctlPoint(tempRect.x, tempRect.y);
		_position_event_(&pe);

		if(allowed)
		{
			_rect = tempRect;
			redraw();
			redrawRect(oldRect);
			//发送 move 事件
			pe.eventType = ctlPositionEventType::move;
			pe.position = ctlPoint(getLeft(), getTop());
			_position_event_(&pe);
			return true;
		}
		return false;
	}
#define STATIC_JUDGE_SIZE(ddir, format)	\
	(((unsigned)dir & (unsigned)ctlDirection::ddir) && getSizeFormat(ctlDirection::ddir) == sizeFormat::format)
#define STATIC_JUDGE_MOVE(ddir, format)	\
	(((unsigned)dir & (unsigned)ctlDirection::ddir) && getMoveFormat(ctlDirection::ddir) == moveFormat::format)
	bool ctlRoot::sizePercent(float cx, float cy, ctlDirection dir)
	{
		if(!isCreated() || !isEnabled() || isPositionLocked()) return false;
		ctlPoint pt(getWidth(), getHeight());
		ctlRect rect = _eventTrans.getParentRect();
		if(STATIC_JUDGE_SIZE(x, percent) /*|| cx <= 0*/) pt.x = int(rect.cx * cx);
		if(STATIC_JUDGE_SIZE(y, percent) /*|| cy <= 0*/) pt.y = int(rect.cy * cy);
		if((unsigned)dir & (unsigned)ctlDirection::x) _sizeX.frac = cx;
		if((unsigned)dir & (unsigned)ctlDirection::y) _sizeY.frac = cy;
		return size(pt);
	}
	bool ctlRoot::sizeRelative(int rightOffset, int bottomOffset, ctlDirection dir, ctlRoot* relation)
	{
		if(!isCreated() || !isEnabled() || isPositionLocked()) return false;
		ctlPoint pt(getWidth(), getHeight());
		ctlRect rect = _eventTrans.getParentRect();
		if(STATIC_JUDGE_SIZE(x, relative)) 
		{
			if(relation != nullptr &&
				(relation == getParent() || relation->getParent() != getParent())) 
			{
				//如果是环状关联
				if(_check_ring_relative_size(relation, this, ctlDirection::x))
					return false;
				if(_sizeX.relation && --_sizeX.relation->_size_related[this] == 0)
					_sizeX.relation->_size_related.erase(this);
				++relation->_size_related[this];
				_sizeX.relation = relation;
			}
			_sizeX.num = rightOffset;
			if(getParent() == getSizeRelation(ctlDirection::x))
				pt.x = rect.cx - _sizeX.num - getLeft();
			else pt.x = getSizeRelation(ctlDirection::x)->getLeft() - _sizeX.num - getLeft();
		}
		if(STATIC_JUDGE_SIZE(y, relative)) 
		{
			if(relation != nullptr &&
				(relation == getParent() || relation->getParent() != getParent())) 
			{
				//如果是环状关联
				if(_check_ring_relative_size(relation, this, ctlDirection::y))
					return false;
				if(_sizeY.relation && --_sizeY.relation->_size_related[this])
					_sizeY.relation->_size_related.erase(this);
				++relation->_size_related[this];
				_sizeY.relation = relation;
			}
			_sizeY.num = bottomOffset;
			if(getParent() == getSizeRelation(ctlDirection::y))
				pt.y = rect.cy - _sizeY.num - getTop();
			else pt.y = getSizeRelation(ctlDirection::y)->getTop() - _sizeY.num - getTop();
		}
		return size(pt);
	}
	bool ctlRoot::movePercent(float x, float y, ctlDirection dir)
	{
		if(!isCreated() || !isEnabled() || isPositionLocked()) return false;
		ctlPoint pt(getLeft(), getTop());
		ctlRect rect = _eventTrans.getParentRect();
		if(STATIC_JUDGE_MOVE(x, percent)) pt.x = int(rect.cx * x);
		if(STATIC_JUDGE_MOVE(y, percent)) pt.y = int(rect.cy * y);
		if((unsigned)dir & (unsigned)ctlDirection::x) _moveX.frac = x;
		if((unsigned)dir & (unsigned)ctlDirection::y) _moveY.frac = y;
		return move(pt);
	}
	bool ctlRoot::moveRelative(int x, int y, ctlDirection dir, ctlRoot* relation)
	{
		if(!isCreated() || !isEnabled() || isPositionLocked()) return false;
		ctlPoint pt(getLeft(), getTop());
		if(STATIC_JUDGE_MOVE(x, relative)) 
		{
			if(relation != nullptr &&
				(relation == getParent() || relation->getParent() != getParent())) 
			{
				//如果是环状关联
				if(_check_ring_relative_move(relation, this, ctlDirection::x))
					return false;
				if(_moveX.relation && --_moveX.relation->_move_related[this])
					_moveX.relation->_move_related.erase(this);
				++relation->_move_related[this];
				_moveX.relation = relation;
			}
			_moveX.num = x;
			pt.x = _calc_move_relative(_moveX.relation, ctlDirection::x).x;
		}
		if(STATIC_JUDGE_MOVE(y, relative)) 
		{
			if(relation != nullptr &&
				(relation == getParent() || relation->getParent() != getParent()))
			{
				//如果是环状关联
				if(_check_ring_relative_move(relation, this, ctlDirection::y))
					return false;
				if(_moveY.relation && --_moveY.relation->_move_related[this])
					_moveY.relation->_move_related.erase(this);
				++relation->_move_related[this];
				_moveY.relation = relation;	
			}
			_moveY.num = y;
			pt.y = _calc_move_relative(_moveY.relation, ctlDirection::y).y;
		}
		return move(pt);
	}
	ctlPoint _get_alignment_point(ctlRoot::moveAlignment align, ctlRect root);
	bool ctlRoot::setMoveAlignment(moveAlignment align, moveAlignment align2)
	{
		if(!isCreated() || !isEnabled()) return false;
		_moveThisAlignment = align;
		_moveRelationAlignment = align2;
		if(getMoveFormat(ctlDirection::x) == moveFormat::relative)
			_moveX.num = -_get_alignment_point(align2, _moveX.relation->getRect()).x + 
			_get_alignment_point(align, this->getRect()).x;
		if(getMoveFormat(ctlDirection::y) == moveFormat::relative)
			_moveY.num = -_get_alignment_point(align2, _moveY.relation->getRect()).y + 
			_get_alignment_point(align, this->getRect()).y;
		return true;
	}
	ctlRectTemplate<float> ctlRoot::getPercentRect() 
	{
		ctlRect parent = _eventTrans.getParentRect();
		return Absolute2Percent(_rect, parent);
	}
#undef STATIC_JUDGE_MOVE
#undef STATIC_JUDGE_SIZE

	bool ctlRoot::setSizeFormat(ctlRoot::sizeFormat value, ctlDirection dir, ctlRoot* relation)
	{
		ctlRectTemplate<float> tr;
		ctlRect rr;
		switch(value)
		{
		case sizeFormat::percent:
			tr = Absolute2Percent(_rect, _eventTrans.getParentRect());
			if((unsigned)dir & (unsigned)ctlDirection::x) _sizeX.frac = tr.cx;
			if((unsigned)dir & (unsigned)ctlDirection::y) _sizeY.frac = tr.cy;
			break;
		case sizeFormat::relative:
			if(relation == nullptr) return false;
			if(relation != getParent() && relation->getParent() != getParent()) 
				return false;
			rr = _eventTrans.getParentRect();
			if((unsigned)dir & (unsigned)ctlDirection::x)
			{
				//如果是环状关联
				if(_check_ring_relative_size(relation, this, ctlDirection::x))
					return false;
				if(_sizeX.relation && --_sizeX.relation->_size_related[this])
					_sizeX.relation->_size_related.erase(this);
				++relation->_size_related[this];
				_sizeX.relation = relation;
				if(relation == getParent()) _sizeX.num = rr.cx - getRight();
				else _sizeX.num = relation->getLeft() - getRight();
			}
			if((unsigned)dir & (unsigned)ctlDirection::y)
			{
				//如果是环状关联
				if(_check_ring_relative_size(relation, this, ctlDirection::y))
					return false;
				if(_sizeY.relation && --_sizeY.relation->_size_related[this])
					_sizeY.relation->_size_related.erase(this);
				++relation->_size_related[this];
				_sizeY.relation = relation;
				if(relation == getParent()) _sizeY.num = rr.cy - getBottom();
				else _sizeY.num = relation->getTop() - getBottom();
			}
			break;
		}
		if((unsigned)dir & (unsigned)ctlDirection::x) _sizeX.format = value;
		if((unsigned)dir & (unsigned)ctlDirection::y) _sizeY.format = value;
		return true;
	}
	bool ctlRoot::setMoveFormat(ctlRoot::moveFormat value, ctlDirection dir, ctlRoot* relation)
	{
		ctlRectTemplate<float> tr;
		switch(value)
		{
		case moveFormat::percent:
			tr = Absolute2Percent(_rect, _eventTrans.getParentRect());
			if((unsigned)dir & (unsigned)ctlDirection::x) _moveX.frac = tr.x;
			if((unsigned)dir & (unsigned)ctlDirection::y) _moveY.frac = tr.y;
			break;
		case moveFormat::relative:
			if(relation == nullptr) return false;
			if(relation != getParent() && relation->getParent() != getParent()) 
				return false;
			if((unsigned)dir & (unsigned)ctlDirection::x)
			{
				//如果是环状关联
				if(_check_ring_relative_move(relation, this, ctlDirection::x))
					return false;
				if(_moveX.relation && --_moveX.relation->_move_related[this])
					_moveX.relation->_move_related.erase(this);
				++relation->_move_related[this];
				_moveX.relation = relation;
				_moveX.num = getLeft() - relation->getLeft();
			}
			if((unsigned)dir & (unsigned)ctlDirection::y)
			{
				//如果是环状关联
				if(_check_ring_relative_move(relation, this, ctlDirection::y))
					return false;
				if(_moveY.relation && --_moveY.relation->_move_related[this])
					_moveY.relation->_move_related.erase(this);
				++relation->_move_related[this];
				_moveY.relation = relation;
				_moveY.num = getTop() - relation->getTop();
			}
			break;
		}
		if((unsigned)dir & (unsigned)ctlDirection::x) _moveX.format = value;
		if((unsigned)dir & (unsigned)ctlDirection::y) _moveY.format = value;
		return true;
	}

	controlList ctlRoot::getChildren(ctlControlType type)
	{
		if(type == ctlControlType::ctlUndefined)
			return _eventTrans.getChildEnumerator();
		controlList list;
		for(ctlRoot* node : _eventTrans.getChildEnumerator())
		{
			if(node->getControlType() == type)
				list.push_back(node);
		}
		return std::move(list);
	}
} 